#include <UnitTest++/UnitTest++.h>
#include "../FunctionCallRecord.h"

using namespace MockItNow;

namespace
{
	TEST (StoresNumberOfFunctionArguments)
	{
		FunctionCallRecord record(0, 0, 10);
		CHECK_EQUAL(10, record.GetNumArguments());
	}

	TEST (HasReturnValueDefaultsToFalse)
	{
		FunctionCallRecord record(0, 0, 10);
		CHECK_EQUAL(false, record.HasReturnValue());
	}

	TEST (HasReturnValueIsTrueAfterSettingReturnValue)
	{
		FunctionCallRecord record(0, 0, 10);
		record.SetReturnValue(false);
		CHECK_EQUAL(true, record.HasReturnValue());
	}

	TEST (CanSetReturnValueOfSameExactType)
	{
		FunctionCallRecord record(0, 0, 10);
		record.SetReturnValue(false);
		CHECK_EQUAL(false, record.GetReturnValue<bool>());
	}

	TEST (DisregardsConstQualifier)
	{
		FunctionCallRecord record(0, 0, 10);
		record.SetReturnValue<const bool>(false);
		CHECK_EQUAL(false, record.GetReturnValue<bool>());
	}

	TEST (DisregardsReferenceQualifier)
	{
		FunctionCallRecord record(0, 0, 10);
		record.SetReturnValue<const bool&>(false);
		CHECK_EQUAL(false, record.GetReturnValue<bool>());
	}

	TEST (ThrowsExceptionWhenGettingMismatchedReturnValueType)
	{
		FunctionCallRecord record(0, 0, 10);
		record.SetReturnValue(false);
		CHECK_THROW(record.GetReturnValue<float>(), std::exception);
	}	

	TEST (CanRecordArgumentOfSameExactType)
	{
		FunctionCallRecord record(0, 0, 1);
		record.RecordArgument(123456);
		CHECK(true);
	}

	TEST (RecordArgumentDisregardsConstQualifier)
	{
		FunctionCallRecord record(0, 0, 1);
		record.RecordArgument(123456);
		CHECK(true);
	}

	TEST (RecordArgumentDisregardsReferenceQualifier)
	{
		FunctionCallRecord record(0, 0, 1);
		record.RecordArgument(123456);
		CHECK(true);
	}

	TEST (ThrowsExceptionWhenReplayingArgumentBeyondArgumentCount)
	{
		FunctionCallRecord record(0, 0, 1);
		CHECK_THROW(record.ReplayArgument(123456), std::exception);
	}

	TEST (ThrowsExceptionWhenReplayingArgumentThatWasNeverCreated)
	{
		FunctionCallRecord record(0, 0, 1);
		CHECK_THROW(record.ReplayArgument(123456), std::exception);
	}

	TEST (CanReplayArgumentOfSameExactType)
	{
		FunctionCallRecord record(0, 0, 1);
		record.RecordArgument(123456);
		record.ReplayArgument(123456);
		CHECK(true);
	}

	TEST (ReplaydArgumentDisregardsConstQualifier)
	{
		FunctionCallRecord record(0, 0, 1);
		record.RecordArgument<const int>(123456);
		record.ReplayArgument(123456);
		CHECK(true);
	}

	TEST (ReplayArgumentDisregardsReferenceQualifier)
	{
		FunctionCallRecord record(0, 0, 1);
		record.RecordArgument<const int&>(123456);
		record.ReplayArgument(123456);
		CHECK(true);
	}

	TEST (ReplayArgumentThrowsExceptionWhenSettingMismatchedType)
	{
		FunctionCallRecord record(0, 0, 1);
		CHECK_THROW(record.ReplayArgument(123456.0f), std::exception);
	}	

	TEST (ThrowsExceptionWhenSettingCompareFunctionBeyondArgumentCount)
	{
		FunctionCallRecord record(0, 0, 1);
		CHECK_THROW(record.SetCompareFunction<int>(1, &CompareByValue<int>), std::exception);
	}

	TEST (ThrowsExceptionWhenSettingCompareFunctionOnArgumentThatWasNeverCreated)
	{
		FunctionCallRecord record(0, 0, 1);
		CHECK_THROW(record.SetCompareFunction<int>(0, &CompareByValue<int>), std::exception);
	}

	TEST (CanSetCompareFunctionOfSameExactType)
	{
		FunctionCallRecord record(0, 0, 1);
		record.RecordArgument(123456);
		record.SetCompareFunction<int>(0, &CompareByValue);
		CHECK(true);
	}

	TEST (SetCompareFunctionDisregardsConstQualifier)
	{
		FunctionCallRecord record(0, 0, 1);
		record.RecordArgument<const int>(123456);
		record.SetCompareFunction<const int>(0, &CompareByValue);
		CHECK(true);
	}

	TEST (SetCompareFunctionDisregardsReferenceQualifier)
	{
		FunctionCallRecord record(0, 0, 1);
		record.RecordArgument<const int&>(123456);
		record.SetCompareFunction<const int&>(0, &CompareByValue);
		CHECK(true);
	}

	TEST (SetCompareFunctionThrowsExceptionWhenSettingMismatchedType)
	{
		FunctionCallRecord record(0, 0, 1);
		CHECK_THROW(record.SetCompareFunction<float>(0, &CompareByValue), std::exception);
	}

	TEST (VerifySucceedsOnCorrectData)
	{
		FunctionCallRecord record(0, 0, 2);

		record.RecordArgument(123456);
		record.RecordArgument(456.0f);

		record.ReplayArgument(123456);
		record.ReplayArgument(456.0f);

		record.Verify();
		CHECK(record.GetReportedFailure().length() == 0);
	}	

	TEST (VerifyThrowsExceptionIfFirstParameterDoesNotMatch)
	{
		FunctionCallRecord record(0, 0, 2);

		record.RecordArgument(123456);
		record.RecordArgument(456.0f);

		record.ReplayArgument(23456);
		record.ReplayArgument(456.0f);

		record.Verify();
		CHECK(record.GetReportedFailure().length() != 0);
	}

	TEST (VerifyThrowsExceptionIfSecondParameterDoesNotMatch)
	{
		FunctionCallRecord record(0, 0, 2);

		record.RecordArgument(123456);
		record.RecordArgument(456.0f);

		record.ReplayArgument(123456);
		record.ReplayArgument(1456.0f);

		record.Verify();
		CHECK(record.GetReportedFailure().length() != 0);
	}

	TEST (VerifySucceedsIfFailWhenCalledIsSet)
	{
		FunctionCallRecord record(0, 0, 2);
		record.SetFailWhenCalled();

		record.RecordArgument(123456);
		record.RecordArgument(456.0f);

		record.Verify();
		CHECK(record.GetReportedFailure().length() == 0);
	}
}
